/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.ui.widgets;

import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

//must implement traverse
/**
 * A Widget that can contain other widgets.
 * <p>
 * By default the container widget does not have a background color or type. For
 * now, scrolling is not supported by the this widget. <br/> <img
 * src="../../../resources/aphro_container.gif">
 * </p>
 * 
 * @author kentelt
 * 
 */
public final class Basket extends TraversableWidget {
	/* Horizontal padding between the widgets in the container */
	private int hPad = 4;
	/* Vertical padding between the widgets in the container */
	private int vPad = 4;
	private Widget currentWidget;
	/* Height of the container that is currently occupied */
	private int estateHeightOccupied = vPad;
	/* Width of the container that is currently occupied */
	private int estateWidthOccupied = hPad;

	/* Parent containers cannot lose focus */
	boolean isParentContainer = true;

	/* Is currently traversing a widget */
	private boolean isTraversing;
	/* The default layout */
	private short layout = LAYOUT_VERTICAL;
	private TraversableWidget traverseWidget;

	/* The widget that is currently selected */
	private int widgetIndex = 0;
	private final Vector widgets;

	/**
	 * 
	 * @param theme
	 *            to be used by the widget
	 */
	public Basket(Theme theme) {
		super(theme, 0, 0);
		widgets = new Vector();
		isInFocus = true;
	}

	/**
	 * Add a widget to the container
	 * <p>
	 * Widgets added to a container does not have to be present in the
	 * <code>paint(Graphics g) </code> of the canvas
	 * </p>
	 * 
	 * @param widget
	 *            to be added to the container
	 * @throws NullPointerException
	 *             if <code>widget</code> is null
	 */
	public void addWidget(Widget widget) {
		if (widget == null) {
			throw new NullPointerException();
		}
		/* set the width and height dynamically */
		if (widgets.size() == 0) {
			width = widget.getWidth() + (hPad * 2);
			height = widget.getHeight() + (vPad * 2);
		} else {
			if (layout == LAYOUT_HORIZONTAL) {
				width += hPad + widget.getWidth();
				if (widget.getHeight() > height) {
					height = widget.getHeight() + (vPad * 2);
				}
			} else {
				height += vPad + widget.getHeight();
				if (widget.getWidth() > width) {
					width = widget.getWidth() + (hPad * 2);
				}
			}
		}
		if (layout == LAYOUT_HORIZONTAL) {
			widget.setY(estateHeightOccupied);
			widget.setX(estateWidthOccupied);
			estateWidthOccupied += hPad + widget.getWidth();
		} else {
			widget.setX(estateWidthOccupied);
			widget.setY(estateHeightOccupied);
			estateHeightOccupied += vPad + widget.getHeight();
		}
		/* remove the focus border if it is a container */
		if (widget instanceof Basket) {
			((TraversableWidget) widget).isInFocus = false;
			/*
			 * remove parent container flag so that the container can lose/gain
			 * focus
			 */
			((Basket) widget).isParentContainer = false;
		}

		widgets.addElement(widget);
		if (currentWidget == null) {
			currentWidget = (Widget) widgets.elementAt(0);
		}
	}

	public void cleanUp() {
		widgets.removeAllElements();
	}

	public boolean keyPressed(int gameActionCode, int key) {
		if (isTraversing) {
			if (!traverseWidget.isInFocus) {
				isTraversing = false;
				this.keyPressed(gameActionCode, key);
			} else {
				traverseWidget.keyPressed(gameActionCode, key);
			}
		} else {
			switch (gameActionCode) {
			case Canvas.LEFT:
				return moveLeft();
			case Canvas.RIGHT:
				return moveRight();

			case Canvas.DOWN:
				return moveDown();
			case Canvas.UP:
				return moveUp();

			case Canvas.FIRE:
				System.out.println("Container fire is pressed");
				break;
			}
		}
		return false;
	}

	public boolean moveDown() {
		return next();
	}

	public boolean moveLeft() {
		return previous();
	}

	public boolean moveRight() {
		return next();
	}

	public boolean moveUp() {
		return previous();
	}

	private boolean next() {
		if (widgetIndex < widgets.size() - 1) {
			widgetIndex++;
			setSelected();
			reDraw();
			return true;
		} else {
			// moveNextFlag++;
			// if (moveNextFlag > 1)
			if (!isParentContainer) {
				isInFocus = false;
				reDraw();
				return false;
			}
		}
		return false;
		// else {
		// widgetIndex = 0;
		// setSelected();
		// }

	}

	private boolean previous() {
		if (widgetIndex > 0) {
			widgetIndex--;
			setSelected();
			reDraw();
			return true;
		} else {
			// moveNextFlag++;
			// if (moveNextFlag > 1)
			if (!isParentContainer)
				isInFocus = false;
			return false;
		}
	}

	public void removeAllWidgets() {
		widgets.removeAllElements();
		estateHeightOccupied = vPad;
		estateWidthOccupied = hPad;
		widgetIndex = 0;
		currentWidget = null;
		reDraw();
	}

	/**
	 * remove the widget at the particular index
	 * 
	 * @param index
	 * @throws IllegalArgumentException
	 *             if the index is < 0 or > number of widgets added
	 */
	public void removeWidget(int index) {
		if (index > widgets.size() || index < 0) {
			throw new IllegalArgumentException("Invalid Index");
		}
		widgets.removeElementAt(index);
		if (widgets.size() > 0) {
			widgetIndex = 0;
			currentWidget = (Widget) widgets.elementAt(widgetIndex);
		}
		repack();
		reDraw();
	}

	// private byte moveNextFlag = 0;

	public void removeWidget(Widget widget) {
		removeWidget(widgets.indexOf(widget));
	}

	public void render(Graphics g) {
		if (!isVisible)
			return;
		capture(g, width, height, true);
		if (widgets.size() > 0) {
			/*
			 * dont draw the selection rectangle if the widget is a container or
			 * if not in focus
			 */
			if (!(currentWidget instanceof Basket) && isInFocus) {
				// g.setColor(fgColor);
				// g.drawRect(currentWidget.x - 2, currentWidget.y - 2,
				// currentWidget.width + 4,
				// currentWidget.height + 4);
				// g.drawRect(currentWidget.x - 1, currentWidget.x - 1,
				// currentWidget.width + 2,
				// currentWidget.height + 2);

				g.setColor(theme.highLightColor);
				g.drawRect(currentWidget.getX() - 2, currentWidget.getY() - 2, currentWidget.getWidth() + 4,
						currentWidget.getHeight() + 4);
				g.drawRect(currentWidget.getX() - 1, currentWidget.getY() - 1, currentWidget.getWidth() + 2,
						currentWidget.getHeight() + 2);
			}

			for (int i = 0; i < widgets.size(); i++)
				((Widget) (widgets.elementAt(i))).render(g);
		}
		release(g, width, height, true);

	}

	// public void setFocus() {
	// super.setFocus();
	// moveNextFlag = 0;
	// }

	/**
	 * 
	 */
	public void repack() {
		estateHeightOccupied = vPad;
		estateWidthOccupied = hPad;
		int biggest = 0;
		Widget widget = null;
		if (layout == LAYOUT_HORIZONTAL) {
			for (int i = 0; i < widgets.size(); i++) {
				widget = (Widget) widgets.elementAt(i);
				if (widget instanceof Basket) {
					((Basket) widget).repack();
				}
				widget.setX(estateWidthOccupied);
				widget.setY(estateHeightOccupied);
				estateWidthOccupied += hPad + widget.width;
				/* find the biggest height for the */
				if (i == 0) {
					// biggest = hPad + widget.height;
					biggest = widget.height;
				}
				if (widget.getHeight() > biggest) {
					// biggest = hPad + widget.height;
					biggest = widget.height;
				}
			}
		} else {/* vertical layout */
			for (int i = 0; i < widgets.size(); i++) {
				widget = (Widget) widgets.elementAt(i);
				if (widget instanceof Basket) {
					((Basket) widget).repack();
				}
				widget.setX(estateWidthOccupied);
				widget.setY(estateHeightOccupied);
				estateHeightOccupied += vPad + widget.getHeight();
				if (i == 0) {
					// biggest = vPad + widget.width;
					biggest = widget.width;
				}
				if (widget.getWidth() > biggest) {
					// biggest = vPad + widget.width;
					biggest = widget.width;
				}
			}
		}
		width = estateWidthOccupied + hPad + (layout == LAYOUT_HORIZONTAL ? 0 : biggest);
		// height = estateHeightOccupied + vPad + (layout == LAYOUT_HORIZONTAL ?
		// biggest : 0);
		height = estateHeightOccupied + (layout == LAYOUT_HORIZONTAL ? biggest : 0);
	}

	/**
	 * 
	 * @param pad
	 * @throws IllegalArgumentException
	 *             if pad <0
	 */
	public void setHPad(int pad) {
		if (pad < 0) {
			throw new IllegalArgumentException("invalid pad");
		}
		hPad = pad;
		repack();
		reDraw();
	}

	/**
	 * Set the widget layout.
	 * <p>
	 * The default layout is vertical
	 * </p>
	 * 
	 * @param layout
	 */
	public void setLayout(short layout) {
		this.layout = layout;
		repack();
		reDraw();
	}

	private void setSelected() {
		currentWidget = (Widget) widgets.elementAt(widgetIndex);
		/* find the next widget that is selectable */
		// if (!currentWidget.canSelect) {
		// System.out.println("Current widget cannot be selected");
		// while (currentWidget.canSelect) {
		// if (widgetIndex + 1 < widgets.size()) {
		// widgetIndex++;
		// } else {
		// widgetIndex = 0;
		// }
		// currentWidget = (Widget) widgets.elementAt(widgetIndex);
		// }
		//
		// }
		if (currentWidget instanceof TraversableWidget) {
			isTraversing = true;
			traverseWidget = (TraversableWidget) currentWidget;
			traverseWidget.setFocus();
		}
	}

	// /*
	// *
	// * Adjust widget's location/container dimensions if any widget has changed
	// * dimensions or removed removed;
	// *
	// * be called if there are any layout changes in the widgets of this
	// * container
	// */
	//
	// public void setSelectorColor(int color) {
	// theme.fgColor = color;
	// reDraw();
	// }

	/**
	 * 
	 * @param pad
	 * @throws IllegalArgumentException
	 *             if pad <0
	 */
	public void setVPad(int pad) {
		if (pad < 0) {
			throw new IllegalArgumentException("invalid pad");
		}
		vPad = pad;
		repack();
		reDraw();
	}

	protected void stateChanged(Widget source) {
		super.stateChanged(this);
		repack();
		reDraw();
	}

	protected boolean traverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout) {
		return false;
	}

	protected void updateModel() {}
}
